/*
 * not type checking this file because flow doesn't play well with
 * dynamically accessing methods on Array prototype
 */

import { def } from '../util/index'

const arrayProto = Array.prototype
// 创建一个对象作为拦截器
export const arrayMethods = Object.create(arrayProto)
// 改变数组自身内容的下面几个方法
const methodsToPatch = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
/**
 * Intercept mutating methods and emit events
 */
methodsToPatch.forEach(function (method) {
  // 缓存原生方法
  const original = arrayProto[method]
  //  接着在arrayMethods上使用object.defineProperty方法将那些可以改变数组自身的7个方法遍历逐个进行封装
  def(arrayMethods, method, function mutator (...args) {  // 用户调用的就是 mutator 方法
    const result = original.apply(this, args)   //由于我们的拦截器是挂载到数组数据的原型上的，所以拦截器中的this就是数据value
  
    const ob = this.__ob__  //vaule上的__ob__就是其对应的Observer类实例
    //有了Observer类实例我们就能访问到它上面的依赖管理器
    
    let inserted
      //再新增元素的情况下，我们只需拿到新增的这个元素， 然后调用observe函数将其转化即可
    switch (method) {
      case 'push':  // 如果是push或unshift方法，那么传入参数就是新增的元素
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2) // 如果是splice方法，那么传入参数列表中下标为2的就是新增的元素
        break
    }
    
    if (inserted) ob.observeArray(inserted)  // 调用observe函数将新增的元素转化成响应式
    // notify change
    ob.dep.notify()
    return result
  })
})
